#region

/* Adoor.NET - Object/Relational mapping framework leveraging ADO.NET`s powerful disconnected mode.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *  
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *  
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#endregion

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Adoor.Object.Domain
{
	/// <summary>
	/// An interface supported by mappers representing an inverse reference.
	/// </summary>
	public interface IInverseReference
	{
		void InitInverseReference();
	}

	/// <summary>
	/// The starting point for reference metadata.
	/// </summary>
	public class ReferenceData
	{
		private string targetRole;
		private string inverseRole;
		private EntityData sourceData;
		private EntityData targetData;
		private bool isSingleReference;
		private string sourceToTargetMultiplicity;
		private string targetToSourceMultiplicity;
		
		public ReferenceData(string targetRole
			, string inverseRole
			, EntityData sourceData
			, EntityData targetData
			, bool isSingleReference
			, string sourceToTargetMultiplicity
			, string targetToSourceMultiplicity)
		{
			this.targetRole = targetRole;
			this.inverseRole = inverseRole;
			this.sourceData = sourceData;
            if (targetData == null)
                throw new NullReferenceException(" targetdata " + targetRole + " not found for source : " + sourceData.EntityType.ToString());
			this.targetData = targetData;
			this.isSingleReference = isSingleReference;
			this.sourceToTargetMultiplicity = sourceToTargetMultiplicity;
			this.targetToSourceMultiplicity = targetToSourceMultiplicity;
		}

		private IDictionary<Type, object> services = new Dictionary<Type, object>();

		public object GetService(Type type)
		{
            object result;
            if (!this.services.TryGetValue(type, out result))
                return null;
			return result;
		}

		public void RegisterService(Type type, object service)
		{
            if (service == null)
                throw new ArgumentNullException("service");
			if (this.services.ContainsKey(type))
				throw new Exception(string.Format("ReferenceData {0}.{1} already contains service {2} ({3}) when registering {4}", this.SourceData.EntityType.Name, this.TargetRole, type.Name, this.services[type].GetType().Name, service.GetType().Name));
			if(this.services.ContainsKey(type))
                throw new Exception(" there are already servicing this type of service ");
			this.services.Add(type, service);
		}

		public string SourceToTargetMultiplicity
		{
			get
			{
				return sourceToTargetMultiplicity;
			}
		}

		public string TargetToSourceMultiplicity
		{
			get
			{
				return targetToSourceMultiplicity;
			}
		}

		public string TargetRole
		{
			get { return this.targetRole; }
		}

		public string InverseRole
		{
			get { return this.inverseRole; }
		}

		public EntityData SourceData
		{
			get { return this.sourceData; }
		}

		public EntityData TargetData
		{
			get { return this.targetData; }
		}

		public bool IsSingleReference
		{
			get { return this.isSingleReference; }
		}

		public ReferenceData Clone(EntityData targetData)
		{
			ReferenceData newRefData = new ReferenceData(this.TargetRole, this.InverseRole, this.SourceData, targetData, this.IsSingleReference, this.SourceToTargetMultiplicity, this.TargetToSourceMultiplicity);
			newRefData.services = new Dictionary<Type, object>();
			return newRefData;
		}

		public event UpdateEventHandler Update;
		
		public void RaiseUpdateEvent(object transaction)
		{
			if(Update !=null)
				Update(this, new UpdateEventArgs(transaction));
		}
	}
}